package megrez.bussiness.schedule.component;

import static org.springframework.util.StringUtils.hasText;

import java.lang.reflect.Method;

import org.springframework.util.ReflectionUtils;

import lombok.ToString;
import megrez.bussiness.schedule.entity.Job;
import megrez.bussiness.schedule.entity.Job.State;
import megrez.bussiness.schedule.entity.JobLog.Level;
import megrez.bussiness.schedule.service.JobService;
import megrez.bussiness.schedule.util.SpringContextHelper;
import megrez.common.util.ExceptionHelper;
import megrez.common.util.Timer;

/**
 * 定时任务
 * 
 * @author Lucky Yang
 * @since 0.0.1
 */
public class SchedulingTask implements Runnable {
    public final Info info;

    public final JobService jobService;
    private Object targetBean;
    private static long counter = 0;
    public final long id = counter++;

    private SchedulingTask(Job job, JobService jobService) {
        this.info = new Info(job.getId(), job.getClassName(), job.getMethodName(), job.getMethodParams(),
                job.getCronExpression());
        this.jobService = jobService;
    }

    public static SchedulingTask of(Job job, JobService jobService) throws ClassNotFoundException {
        SchedulingTask rslt = new SchedulingTask(job, jobService);
        rslt.initBean();
        return rslt;
    }

    private void initBean() throws ClassNotFoundException {
        this.targetBean = SpringContextHelper.getBean(Class.forName(info.className));

        jobService.createLog(info.jobId, Level.STARTED, formatMessage("启动任务"));
    }

    @Override
    public void run() {
        if (this.targetBean == null) {
            return;
        }

        Timer timer = new Timer();
        try {
            jobService.updateJobState(info.jobId, State.RUNNING);
            jobService.createLog(info.jobId, Level.RUNNING, formatMessage("开始执行任务:" + info.toString()));

            Method method = null;
            if (hasText(info.methodParams)) {
                method = targetBean.getClass().getDeclaredMethod(info.methodName, String.class);
            } else {
                method = targetBean.getClass().getDeclaredMethod(info.methodName);
            }

            ReflectionUtils.makeAccessible(method);
            if (hasText(info.methodParams)) {
                method.invoke(targetBean, info.methodParams);
            } else {
                method.invoke(targetBean);
            }
            jobService.createLog(info.jobId, Level.COMPLETE, formatMessage("任务执行结束"), timer.duration());
            jobService.updateJobState(info.jobId, State.STARTED);
        } catch (Exception e) {
            jobService.createLog(info.jobId, Level.ERROR, formatMessage(ExceptionHelper.stacktraceToString(e)),
                    timer.duration());
            jobService.updateJobState(info.jobId, State.ERROR);
        }

    }

    private String formatMessage(String message) {
        return String.format("[TASK-%s]%s", String.valueOf(id), message);
    }

    public void close() {
        this.jobService.updateJobState(info.jobId, State.STOPPED);
        this.jobService.createLog(info.jobId, Level.STOPPED, formatMessage("任务关闭"));        
    }

    @ToString
    protected static class Info {
        public final Long jobId;
        public final String className;
        public final String methodName;
        public final String methodParams;
        public final String cronExpression;

        public Info(Long jobId, String className, String methodName, String methodParams, String cronExpression) {
            this.jobId = jobId;
            this.className = className;
            this.methodName = methodName;
            this.methodParams = methodParams;
            this.cronExpression = cronExpression;
        }
    }


}
